<?php
namespace PsiFramework\Classes\Util\Database\Builder;

import("Classes.Util.Database.SqlQuery");
import("Classes.Util.Database.Query.SqlColumn");
import("Classes.Util.Database.Query.SqlLimit");
import("Classes.Util.Database.Query.SqlTable");
import("Classes.Util.Database.Query.SqlOperation");
import("Classes.Util.Database.Filters.Paginator");

use \PsiFramework\Classes\Util\Database\SqlQuery;
use \PsiFramework\Classes\Util\Database\Query\SqlColumn;
use \PsiFramework\Classes\Util\Database\Query\SqlJoin;
use \PsiFramework\Classes\Util\Database\Query\SqlLimit;
use \PsiFramework\Classes\Util\Database\Query\SqlParameter;
use \PsiFramework\Classes\Util\Database\Query\SqlTable;
use \PsiFramework\Classes\Util\Database\Query\SqlOperation;
use \PsiFramework\Classes\Util\Database\Query\SqlValue;
use \PsiFramework\Classes\Util\Database\Filters\Paginator;

/**
 * PsiFramework
 * Php simple Framework
 *
 * @author Remi San
 * @version 0.9
 */

/**
 * The QueryBuilder class allows to build a sql query
 *
 * @package Util.Database.Builder
 */
class QueryBuilder
{

    protected /*SqlQuery*/ $_query ;

    public function __construct()
    {
        $this->_query = new SqlQuery();
    }

    public function createSelectQuery()
    {
        $this->_query->setType(SqlQuery::$select);
    }

    public function createInsertQuery()
    {
        $this->_query->setType(SqlQuery::$insert);
    }

    public function createUpdateQuery()
    {
        $this->_query->setType(SqlQuery::$update);
    }

    public function createDeleteQuery()
    {
        $this->_query->setType(SqlQuery::$delete);
    }

    public function addSelectColumn(SqlParameter $column)
    {
        if ($column instanceof SqlColumn) {
            if (is_null($column->getTable())) {
                $column->setTable($this->_query->getTable());
            } else if (is_null($this->_query->getTable())) {
                $this->_query->setTable($column->getTable());
            }
        }
        $this->_query->addParameter($column);
    }

    public function addJoin(SqlJoin $join)
    {
        //TODO regarder le join pour mettre à jour des champs si besoin
        $this->_query->addJoin($join);
    }

    public function setTable(SqlTable $table)
    {
        $this->_query->setTable($table);
    }

    public function addParameter($parameter)
    {
        $this->_query->addParameter($parameter);
    }

    public function addColumnValue(SqlColumn $column, SqlValue $value=null)
    {
        if (is_null($column)) {
            throw new \Exception("Bad column !");
        }

        $operation = new SqlOperation(SqlOperation::$equal);
        $operation->addParameter($column);
        $operation->addParameter($value);

        $this->_query->addParameter($operation);
    }

    public function addWhereClause(SqlOperation $operation)
    {
        $whereClause = $this->_query->getWhereClause();
        if ($whereClause != null) {
            if ($whereClause->getOperator() == SqlOperation::$and) {
                $whereClause->addParameter($operation);
            } else {
                $newOperation = new SqlOperation(SqlOperation::$and);
                $newOperation->addParameter($whereClause);
                $newOperation->addParameter($operation);
                $whereClause = $newOperation ;
            }
        } else {
            $whereClause = $operation ;
        }
        $this->_query->setWhereClause($whereClause);
    }

    public function addPagination(Paginator $paginator)
    {
        if (is_null($paginator)) {
            return ;
        }
        
        if (is_null($paginator->getOrders())
            &&count($paginator->getOrders())>0
        ) {
            return ;
        }

        if (!is_null($paginator->getNbResults())) {
            $limit = new SqlLimit($paginator->getNbResults());
            if (!is_null($paginator->getPage())) {
                $page = $paginator->getPage()-1 ;
                $skip = $page * $paginator->getNbResults();
                $limit->setSkip($skip);
            }
            $this->_query->setLimit($limit);
        }

        foreach ($paginator->getOrders() as $order) {
            $this->_query->addOrderClause($order);
        }
    }

    public function buildQuery()
    {
        return $this->_query ;
    }
}

